#include "MainFrame.h"
#include "wx/stdpaths.h"

#if defined _WIN32
#include <objidlbase.h>
#include <vcruntime_new.h>
#include <Windows.h>
#include <Dbt.h>
#include <devguid.h>
// 具体的设备 GUID 需要 initguid, 如 usbiodef
#include <initguid.h>
// USB 设备
// GUID_DEVINTERFACE_USB_DEVICE
#include <usbiodef.h>
// HID 人机交互设备-鼠标键盘等
// #include <hidclass.h>
// 键盘 GUID_DEVINTERFACE_KEYBOARD
// #include <ntddkbd.h>
// 鼠标 GUID_DEVINTERFACE_MOUSE
// #include <ntddmou.h>
#endif

#include "MyCommon.h"

#define PANEL_HEIGHT    230

wxDEFINE_EVENT(mEVT_MAINFRAME_PROGRESS, MyEventMainFrame);
wxDEFINE_EVENT(mEVT_DEVICE_ARRIVAL, MyEventMainFrame);
wxDEFINE_EVENT(mEVT_DEVICE_REMOVED, MyEventMainFrame);

wxBEGIN_EVENT_TABLE(MainFrame, wxFrame)
    EVT_MENU(wxID_ABOUT, MainFrame::OnAbout)
    EVT_MENU(wxID_EXIT, MainFrame::OnExit)
    EVT_MENU(wxID_SAVE, MainFrame::OnSaveParam)
    EVT_CLOSE(MainFrame::OnClose)
    EVT_MENU(MainFrame::ID_MENU_VIEW_EQUALIZER,MainFrame::OnMenuView)
    EVT_MENU(MainFrame::ID_MENU_VIEW_LOG,MainFrame::OnMenuView)
    EVT_MENU(MainFrame::ID_MENU_VIEW_REVERB,MainFrame::OnMenuView)
    EVT_MENU(MainFrame::ID_MENU_VIEW_CHORUS,MainFrame::OnMenuView)
    EVT_MENU(MainFrame::ID_MENU_VIEW_DELAY,MainFrame::OnMenuView)
    EVT_MENU(MainFrame::ID_MENU_VIEW_DISTORTION,MainFrame::OnMenuView)
    EVT_MENU(MainFrame::ID_MENU_VIEW_COMPRESS,MainFrame::OnMenuView)
    EVT_TIMER(MainFrame::ID_TIM_USB_DELAY, MainFrame::OnTimerUSBDelay)
    M_EVT_MAINFRAME_PROCESS(ID_DIALOG_PROCESS, MainFrame::OnProcessUpdate)
    M_EVT_MAINFRAME_ARRIVAL(wxID_ANY, MainFrame::OnUsbArrival)
    M_EVT_MAINFRAME_REMOVED(wxID_ANY, MainFrame::OnUsbRemoved)
#if PANEL_EN_REVERB
    M_EVT_REVERB(wxID_ANY, MainFrame::OnReverbParamChange)
    M_EVT_REVERB_ENABLE(wxID_ANY, MainFrame::OnReverbParamChange)
    M_EVT_REVERB_DAMPING(wxID_ANY, MainFrame::OnReverbParamChange)
    M_EVT_REVERB_DRY(wxID_ANY, MainFrame::OnReverbParamChange)
    M_EVT_REVERB_FEEDBACK(wxID_ANY, MainFrame::OnReverbParamChange)
    M_EVT_REVERB_TONE(wxID_ANY, MainFrame::OnReverbParamChange)
    M_EVT_REVERB_WET(wxID_ANY, MainFrame::OnReverbParamChange)
#endif
#if PANEL_EN_DELAY
    M_EVT_DELAY(wxID_ANY, MainFrame::OnDelayParamChange)
    M_EVT_DELAY_FEEDBACK(wxID_ANY, MainFrame::OnDelayParamChange)
    M_EVT_DELAY_WET(wxID_ANY, MainFrame::OnDelayParamChange)
    M_EVT_DELAY_TIME(wxID_ANY, MainFrame::OnDelayParamChange)
    M_EVT_DELAY_ENABLE(wxID_ANY, MainFrame::OnDelayParamChange)
    M_EVT_DELAY_TONE(wxID_ANY, MainFrame::OnDelayParamChange)
#endif
#if PANEL_EN_WAH
    M_EVT_WAH(wxID_ANY, MainFrame::OnWahParamChange)
    M_EVT_WAH_ENABLE(wxID_ANY, MainFrame::OnWahParamChange)
    M_EVT_WAH_SPEED(wxID_ANY, MainFrame::OnWahParamChange)
    M_EVT_WAH_FILTER_FREQ_WIDTH(wxID_ANY, MainFrame::OnWahParamChange)
    M_EVT_WAH_FILTER_FREQ_CENTER(wxID_ANY, MainFrame::OnWahParamChange)
    M_EVT_WAH_FILTER_Q(wxID_ANY, MainFrame::OnWahParamChange)
    M_EVT_WAH_FILTER_GAIN(wxID_ANY, MainFrame::OnWahParamChange)
#endif
#if PANEL_EN_CHORUS
    M_EVT_CHORUS(wxID_ANY, MainFrame::OnChorusParamChange)
    M_EVT_CHORUS_ENABLE(wxID_ANY, MainFrame::OnChorusParamChange)
    M_EVT_CHORUS_DRY(wxID_ANY, MainFrame::OnChorusParamChange)
    M_EVT_CHORUS_WET(wxID_ANY, MainFrame::OnChorusParamChange)
    M_EVT_CHORUS_PITCH(wxID_ANY, MainFrame::OnChorusParamChange)
    M_EVT_CHORUS_RATE(wxID_ANY, MainFrame::OnChorusParamChange)
    M_EVT_CHORUS_TONE(wxID_ANY, MainFrame::OnChorusParamChange)
#endif

#if PANEL_EN_DISTORTION
    M_EVT_DISTORTION(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_ENABLE(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_TONE(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_DRIVE(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_GAIN(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_LEVEL(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_FREQ(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_WIDTH(wxID_ANY, MainFrame::OnDistortionParamChange)
    M_EVT_DISTORTION_EQ(wxID_ANY, MainFrame::OnDistortionParamChange)
#endif

#if PANEL_EN_COMPRESSOR
    M_EVT_COMPRESSOR(wxID_ANY, MainFrame::OnCompressorParamChange)
    M_EVT_COMPRESSOR_ATTACK_TIME(wxID_ANY, MainFrame::OnCompressorParamChange)
    M_EVT_COMPRESSOR_RELEASE_TIME(wxID_ANY, MainFrame::OnCompressorParamChange)
    M_EVT_COMPRESSOR_THRESHOLD(wxID_ANY, MainFrame::OnCompressorParamChange)
    M_EVT_COMPRESSOR_RATIO(wxID_ANY, MainFrame::OnCompressorParamChange)
    M_EVT_COMPRESSOR_ENABLE(wxID_ANY, MainFrame::OnCompressorParamChange)
    M_EVT_COMPRESSOR_POSTGAIN(wxID_ANY, MainFrame::OnCompressorParamChange)
#endif

#if PANEL_EN_PRESET
    M_EVT_PRESET_INDEX(wxID_ANY,MainFrame::OnPresetParamChange)
    M_EVT_PRESET_EFFECT_STATUS_UPDATE(wxID_ANY,MainFrame::OnPresetParamChange)
#endif

wxEND_EVENT_TABLE()

MainFrame::MainFrame()
    : wxFrame(nullptr, wxID_ANY, wxT("DOUBLE声学"))
{

#if PANEL_EN_LOGGER
    panel_log = new PanelLogger(wxT("Log"),ID_PANEL_LOG,this);
#endif

    wxMenu *menuFile = new wxMenu;
    // menuFile->Append(ID_Hello, "&Hello...\tCtrl-H","Help string shown in status bar for this menu item");
    // menuFile->AppendSeparator();
    menuFile->Append(wxID_SAVE, "&Save\tAlt-S", "Save effect param");
    menuFile->Append(wxID_EXIT);

    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);

    wxMenu *menuView = new wxMenu;
#if PANEL_EN_LOGGER
    menuView->AppendCheckItem(ID_MENU_VIEW_LOG, wxT("&Log"),wxT("Show log panel"));
    menuView->Check(ID_MENU_VIEW_LOG, true);
#endif
#if PANEL_EN_REVERB
    menuView->AppendCheckItem(ID_MENU_VIEW_REVERB, wxT("&Reverb"),wxT("Show reverb panel"));
    menuView->Check(ID_MENU_VIEW_REVERB, true);
#endif
#if PANEL_EN_EQUALIZER
    menuView->AppendCheckItem(ID_MENU_VIEW_EQUALIZER, wxT("&Equalizer"),wxT("Show equalizer panel"));
    menuView->Check(ID_MENU_VIEW_EQUALIZER, true);
#endif
#if PANEL_EN_CHORUS
    menuView->AppendCheckItem(ID_MENU_VIEW_CHORUS, wxT("&Chorus"),wxT("Show chorus panel"));
    menuView->Check(ID_MENU_VIEW_CHORUS, true);
#endif
#if PANEL_EN_DELAY
    menuView->AppendCheckItem(ID_MENU_VIEW_DELAY, wxT("&Delay"),wxT("Show delay panel"));
    menuView->Check(ID_MENU_VIEW_DELAY, true);
#endif
#if PANEL_EN_WAH
    menuView->AppendCheckItem(ID_MENU_VIEW_WAH, wxT("&Wah"),wxT("Show wah panel"));
    menuView->Check(ID_MENU_VIEW_WAH, true);
#endif
#if PANEL_EN_DISTORTION
    menuView->AppendCheckItem(ID_MENU_VIEW_DISTORTION, wxT("&Distortion"),wxT("Show distortion panel"));
    menuView->Check(ID_MENU_VIEW_DISTORTION, true);
#endif
#if PANEL_EN_COMPRESSOR
    menuView->AppendCheckItem(ID_MENU_VIEW_COMPRESS, wxT("&Compressor"),wxT("Show compressor panel"));
    menuView->Check(ID_MENU_VIEW_COMPRESS, true);
#endif
#if PANEL_EN_PRESET
    menuView->AppendCheckItem(ID_MENU_VIEW_PRESET, wxT("&Preset"),wxT("Show preset panel"));
    menuView->Check(ID_MENU_VIEW_PRESET, true);
#endif

    menuBar = new wxMenuBar;
    menuBar->Append(menuFile, wxT("&File"));
    menuBar->Append(menuView, wxT("&View"));
    menuBar->Append(menuHelp, wxT("&Help"));

    SetMenuBar( menuBar );

    CreateStatusBar();
    SetStatusText(wxT("Welcome!"));

///////////////

    current_preset_num = 0;
    wxStandardPaths standardPaths = wxStandardPaths::Get();
    wxString documentsDir = standardPaths.GetDocumentsDir();
    config_file_full_path = wxString::Format("%s/%s/%s",documentsDir.c_str(),"Double_Tool",config_file_name);
    // initXmlConfigFile(config_file_full_path);
    data_save = new DataSave(config_file_full_path);
    //S1 Max
    // usb_device_vid = 0x8085;
    // usb_device_pid = 0x1001;
    // usb_device_in_ep  = 0x82;
    // usb_device_out_ep = 0x03;
    // usb_device_interface_num = 0;
    //EG01
    usb_device_vid = 0x8085;
    usb_device_pid = 0x0020;
    usb_device_in_ep  = 0x05;
    usb_device_out_ep = 0x06;
    usb_device_interface_num = 3;
    usb_comm = new USBCommunication(usb_device_vid, usb_device_pid, usb_device_interface_num);
    cmd_proc = new CommandProcess(usb_comm, usb_device_interface_num, usb_device_in_ep, usb_device_out_ep);


#if PANEL_EN_REVERB
    panel_reverb = new PanelReverb(wxT("Reverb"),data_save->GetEffectParamNode(DataSave::NODE_REVERB), ID_PANEL_REVERB,this);
#endif
#if PANEL_EN_CHORUS
    panel_chorus = new PanelChorus(wxT("Chorus"),data_save->GetEffectParamNode(DataSave::NODE_CHORUS),ID_PANEL_CHORUS,this);
#endif
#if PANEL_EN_DELAY
    panel_delay = new PanelDelay(wxT("Delay"),data_save->GetEffectParamNode(DataSave::NODE_DELAY),ID_PANEL_DELAY,this);
#endif
#if PANEL_EN_WAH
    panel_wah = new PanelWah(wxT("Auto Wah"),data_save->GetEffectParamNode(DataSave::NODE_WAH),ID_PANEL_WAH,this);
#endif
#if PANEL_EN_DISTORTION
    panel_distortion   = new PanelDistortion(wxT("Distortion"),data_save->GetEffectParamNode(DataSave::NODE_DISTORTION),ID_PANEL_DISTORTION,this);
#endif
#if PANEL_EN_COMPRESSOR
    panel_compress = new PanelCompressor(wxT("Compressoror"),data_save->GetEffectParamNode(DataSave::NODE_COMPRESS),ID_PANEL_COMPRESSOR,this);
#endif
#if PANEL_EN_EQUALIZER
    panel_eq = new PanelEqualizer(wxT("Graphic EQ"),48000,ID_PANEL_EQUALIZER,this);
#endif
#if PANEL_EN_PRESET
    panel_preset = new PanelPreset(wxT("Preset"),ID_PANEL_PRESET,this);
#endif
    // MyKnob *knob = new MyKnob(this, -1);

    auiManager = new wxAuiManager(this);
    auiManager->Update();
#if PANEL_EN_LOGGER
    auiManager->AddPane(panel_log,panel_log->GetPaneInfo());
    auiManager->GetPane(panel_log).MinSize(100, 200);
    auiManager->GetPane(panel_log).Resizable();
    auiManager->GetPane(panel_log).Direction(wxAUI_DOCK_BOTTOM);
#endif
#if PANEL_EN_REVERB
    auiManager->AddPane(panel_reverb,panel_reverb->GetPaneInfo());
    auiManager->GetPane(panel_reverb).MinSize(100,PANEL_HEIGHT);
    auiManager->GetPane(panel_reverb).Resizable();
    auiManager->GetPane(panel_reverb).Direction(wxAUI_DOCK_TOP);
#endif
#if PANEL_EN_CHORUS
    auiManager->AddPane(panel_chorus,panel_chorus->GetPaneInfo());
    auiManager->GetPane(panel_chorus).MinSize(100,PANEL_HEIGHT);
    auiManager->GetPane(panel_chorus).Resizable();
    auiManager->GetPane(panel_chorus).Direction(wxAUI_DOCK_TOP);
#endif
#if PANEL_EN_DELAY
    auiManager->AddPane(panel_delay,panel_delay->GetPaneInfo());
    auiManager->GetPane(panel_delay).MinSize(100,PANEL_HEIGHT);
    auiManager->GetPane(panel_delay).Resizable();
    auiManager->GetPane(panel_delay).Direction(wxAUI_DOCK_TOP);
#endif
#if PANEL_EN_DISTORTION
    auiManager->AddPane(panel_distortion,panel_distortion->GetPaneInfo());
    auiManager->GetPane(panel_distortion).MinSize(100,PANEL_HEIGHT);
    auiManager->GetPane(panel_distortion).Resizable();
    auiManager->GetPane(panel_distortion).Direction(wxAUI_DOCK_TOP);
#endif
#if PANEL_EN_COMPRESSOR
    auiManager->AddPane(panel_compress,panel_compress->GetPaneInfo());
    auiManager->GetPane(panel_compress).MinSize(100,PANEL_HEIGHT);
    auiManager->GetPane(panel_compress).Resizable();
    auiManager->GetPane(panel_compress).Direction(wxAUI_DOCK_TOP);
#endif
#if PANEL_EN_EQUALIZER
    auiManager->AddPane(panel_eq,panel_eq->GetPaneInfo());
    auiManager->GetPane(panel_eq).MinSize(400, 100);
    auiManager->GetPane(panel_eq).Resizable();
#endif
#if PANEL_EN_WAH
    auiManager->AddPane(panel_wah,panel_wah->GetPaneInfo());
    auiManager->GetPane(panel_wah).MinSize(100,PANEL_HEIGHT);
    auiManager->GetPane(panel_wah).Resizable();
    auiManager->GetPane(panel_wah).Direction(wxAUI_DOCK_TOP);
#endif
#if PANEL_EN_PRESET
    auiManager->AddPane(panel_preset,panel_preset->GetPaneInfo());
    auiManager->GetPane(panel_preset).MinSize(550,PANEL_HEIGHT);
    auiManager->GetPane(panel_preset).Resizable();
    auiManager->GetPane(panel_preset).Direction(wxAUI_DOCK_LEFT);
#endif
    // auiManager->AddPane(knob);
    // auiManager->GetPane(knob).MinSize(100, 100);
    // auiManager->GetPane(knob).Resizable();

    auiManager->Update();
    auiManager->Connect(wxEVT_AUI_PANE_CLOSE, wxAuiManagerEventHandler(MainFrame::OnAUIPanelClose), nullptr, this);
#if PANEL_EN_EQUALIZER
    panel_eq->AddFilter(Lowshelf,100,20,0.747);
    panel_eq->AddFilter(Peak,200,10,0.747);
    panel_eq->AddFilter(Peak,600,-10,0.747);
    panel_eq->AddFilter(Peak,1000,15,0.747);
    panel_eq->AddFilter(Peak,2000,-13,0.747);
    panel_eq->AddFilter(Peak,5000,24,0.747);
    panel_eq->AddFilter(Peak,8000,6,0.747);
    panel_eq->AddFilter(Highshelf,16000,-10,0.747);
#endif


    tim_usb_delay = new wxTimer(this, ID_TIM_USB_DELAY);
    tim_usb_delay->Start(200,true);

#if defined _WIN32
    RegisterUSBDeviceNotification();
#elif defined __APPLE__
    RegisterUSBDeviceNotification();
#else
    if(usb_comm->StartHotplugCheck() == false)
    {
        wxLogInfo("register hotplug failed");
    }
#endif

    proc_dig = new ProgressDialog(this,wxID_ANY,wxT("Syncing device data"),wxT(""),100);
    // proc_dig->Show(true);
    // proc_dig.ShowModal();

    mainframe_event.SetEventObject(this);
}

MainFrame::~MainFrame()
{
    // delete menuBar;
    // delete auiManager;
    // delete panel_reverb;
    // delete panel_eq;
    // delete panel_log;
    delete data_save;
    delete proc_dig;
#if defined __APPLE__
    IONotificationPortDestroy(notify_prot);
#endif
}

void MainFrame::OnExit(wxCommandEvent& event)
{
    Close(true);
    event.Skip();
}

void MainFrame::OnClose(wxCloseEvent& event)
{
    // xmlConfigSave();
    data_save->Save();
    event.Skip();
}

void MainFrame::OnAbout(wxCommandEvent& event)
{
    wxMessageBox(wxT("DOUBLE MUSIC"),
                 wxT("About"), wxOK | wxICON_INFORMATION);
}

void MainFrame::OnSaveParam(wxCommandEvent& event)
{
    data_save->Save();
    if(cmd_proc->save_param_to_device() == CommandProcess::SUCCESS)
    {
        wxMessageBox(wxT("Save success"),wxT("Save"), wxOK | wxICON_INFORMATION);
    }
    else
    {
        wxMessageBox(wxT("Save failed"),wxT("Save"), wxOK | wxICON_ERROR);
    }
}

void MainFrame::OnMenuView(wxCommandEvent& event)
{
    int id = event.GetId();
    switch (id)
    {
#if PANEL_EN_LOGGER
    case ID_MENU_VIEW_LOG:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_log);
                    panel_log->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_log, panel_log->GetPaneInfo());
                    auiManager->GetPane(panel_log).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_log).Resizable();
                    auiManager->GetPane(panel_log).Float();
                    int w,h;
                    panel_log->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_log).FloatingPosition(w/2 - panel_log->GetMinWidth()/2,h/2 - panel_log->GetMinHeight()/2);
                    panel_log->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_REVERB
    case ID_MENU_VIEW_REVERB:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_reverb);
                    panel_reverb->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_reverb, panel_reverb->GetPaneInfo());
                    auiManager->GetPane(panel_reverb).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_reverb).Resizable();
                    auiManager->GetPane(panel_reverb).Float();
                    int w,h;
                    panel_reverb->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_reverb).FloatingPosition(w/2 - panel_reverb->GetMinWidth()/2,h/2 - panel_reverb->GetMinHeight()/2);
                    panel_reverb->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_CHORUS
    case ID_MENU_VIEW_CHORUS:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_chorus);
                    panel_chorus->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_chorus, panel_chorus->GetPaneInfo());
                    auiManager->GetPane(panel_chorus).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_chorus).Resizable();
                    auiManager->GetPane(panel_chorus).Float();
                    int w,h;
                    panel_chorus->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_chorus).FloatingPosition(w/2 - panel_chorus->GetMinWidth()/2,h/2 - panel_chorus->GetMinHeight()/2);
                    panel_chorus->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_DELAY
    case ID_MENU_VIEW_DELAY:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_delay);
                    panel_delay->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_delay, panel_delay->GetPaneInfo());
                    auiManager->GetPane(panel_delay).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_delay).Resizable();
                    auiManager->GetPane(panel_delay).Float();
                    int w,h;
                    panel_delay->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_delay).FloatingPosition(w/2 - panel_delay->GetMinWidth()/2,h/2 - panel_delay->GetMinHeight()/2);
                    panel_delay->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_WAH
    case ID_MENU_VIEW_WAH:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_wah);
                    panel_wah->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_wah, panel_wah->GetPaneInfo());
                    auiManager->GetPane(panel_wah).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_wah).Resizable();
                    auiManager->GetPane(panel_wah).Float();
                    int w,h;
                    panel_wah->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_wah).FloatingPosition(w/2 - panel_wah->GetMinWidth()/2,h/2 - panel_wah->GetMinHeight()/2);
                    panel_wah->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_DISTORTION
    case ID_MENU_VIEW_DISTORTION:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_distortion);
                    panel_distortion->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_distortion, panel_distortion->GetPaneInfo());
                    auiManager->GetPane(panel_distortion).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_distortion).Resizable();
                    auiManager->GetPane(panel_distortion).Float();
                    int w,h;
                    panel_distortion->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_distortion).FloatingPosition(w/2 - panel_distortion->GetMinWidth()/2,h/2 - panel_distortion->GetMinHeight()/2);
                    panel_distortion->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_COMPRESSOR
    case ID_MENU_VIEW_COMPRESS:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_compress);
                    panel_compress->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_compress, panel_compress->GetPaneInfo());
                    auiManager->GetPane(panel_compress).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_compress).Resizable();
                    auiManager->GetPane(panel_compress).Float();
                    int w,h;
                    panel_compress->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_compress).FloatingPosition(w/2 - panel_compress->GetMinWidth()/2,h/2 - panel_compress->GetMinHeight()/2);
                    panel_compress->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_EQUALIZER
    case ID_MENU_VIEW_EQUALIZER:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_eq);
                    panel_eq->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_eq, panel_eq->GetPaneInfo());
                    auiManager->GetPane(panel_eq).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_eq).Resizable();
                    auiManager->GetPane(panel_eq).Float();
                    int w,h;
                    panel_eq->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_eq).FloatingPosition(w/2 - panel_eq->GetMinWidth()/2,h/2 - panel_eq->GetMinHeight()/2);
                    panel_eq->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif
#if PANEL_EN_PRESET
    case ID_MENU_VIEW_PRESET:
        {
            wxMenuItem* menuItem = menuBar->FindItem(id);
            if(menuItem)
            {
                bool isChecked = menuItem->IsChecked();
                if(!isChecked)
                {
                    auiManager->DetachPane(panel_preset);
                    panel_preset->SetShow(false);
                }
                else
                {
                    auiManager->AddPane(panel_preset, panel_preset->GetPaneInfo());
                    auiManager->GetPane(panel_preset).MinSize(100,PANEL_HEIGHT);
                    auiManager->GetPane(panel_preset).Resizable();
                    auiManager->GetPane(panel_preset).Float();
                    int w,h;
                    panel_preset->GetParent()->GetSize(&w,&h);
                    auiManager->GetPane(panel_preset).FloatingPosition(w/2 - panel_preset->GetMinWidth()/2,h/2 - panel_preset->GetMinHeight()/2);
                    panel_preset->SetShow(true);
                }
                auiManager->Update();
            }
        }
        break;
#endif

    default:
        break;
    }
}

void MainFrame::OnAUIPanelClose(wxAuiManagerEvent& event)
{
    int id = event.GetPane()->window->GetId();

    switch (id)
    {
#if PANEL_EN_LOGGER
        case ID_PANEL_LOG:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_LOG);
            menuItem->Check(false);
            auiManager->DetachPane(panel_log);
            panel_log->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_REVERB
        case ID_PANEL_REVERB:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_REVERB);
            menuItem->Check(false);
            auiManager->DetachPane(panel_reverb);
            panel_reverb->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_CHORUS
        case ID_PANEL_CHORUS:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_CHORUS);
            menuItem->Check(false);
            auiManager->DetachPane(panel_chorus);
            panel_chorus->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_DELAY
        case ID_PANEL_DELAY:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_DELAY);
            menuItem->Check(false);
            auiManager->DetachPane(panel_delay);
            panel_delay->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_WAH
        case ID_PANEL_WAH:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_WAH);
            menuItem->Check(false);
            auiManager->DetachPane(panel_wah);
            panel_wah->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_DISTORTION
        case ID_PANEL_DISTORTION:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_DISTORTION);
            menuItem->Check(false);
            auiManager->DetachPane(panel_distortion);
            panel_distortion->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_COMPRESSOR
        case ID_PANEL_COMPRESSOR:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_COMPRESS);
            menuItem->Check(false);
            auiManager->DetachPane(panel_compress);
            panel_compress->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_EQUALIZER
        case ID_PANEL_EQUALIZER:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_EQUALIZER);
            menuItem->Check(false);
            auiManager->DetachPane(panel_eq);
            panel_eq->SetShow(false);
        }
        break;
#endif
#if PANEL_EN_PRESET
        case ID_PANEL_PRESET:
        {
            wxMenuItem* menuItem = menuBar->FindItem(ID_MENU_VIEW_PRESET);
            menuItem->Check(false);
            auiManager->DetachPane(panel_preset);
            panel_preset->SetShow(false);
        }
        break;
#endif

        default:
        break;
    }
}


#if defined _WIN32

WXLRESULT MainFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
    // PMSG msg = (PMSG)message;
    UINT msgType = message;
    if(msgType == WM_DEVICECHANGE)
    {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
        switch(wParam)
        {
        case DBT_DEVICETYPESPECIFIC:
        {
            std::cout << "DBT_DEVICETYPESPECIFIC " << std::endl ;
            break;
        }
        case DBT_DEVICEARRIVAL:
            if (lpdb -> dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                PDEV_BROADCAST_DEVICEINTERFACE pDevInf  = PDEV_BROADCAST_DEVICEINTERFACE(lpdb);
                wxString device_name = wxString((const wchar_t *)pDevInf->dbcc_name).ToUTF8();
                wxString strVID,strPID,strSerialNumber;
                int share_0 = device_name.find(wxT("#"));
                int share_1 = device_name.find(wxT("#"),share_0+1);
                int share_2 = device_name.find(wxT("#"),share_1+1);
                strVID = device_name.substr(device_name.find(wxT("VID_"))+4,4);
                strPID = device_name.substr(device_name.find(wxT("PID_"))+4,4);
                strSerialNumber = device_name.substr(share_1+1,share_2-share_1-1);
                uint32_t vid=0,pid=0;
                bool ok;
                ok = strVID.ToUInt(&vid,16);
                ok = strPID.ToUInt(&pid,16);
                USBDeviceArrival((int)vid,(int)pid,strSerialNumber);
            }
            break;
        case DBT_DEVICEREMOVECOMPLETE:
            if (lpdb -> dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                PDEV_BROADCAST_DEVICEINTERFACE pDevInf  = PDEV_BROADCAST_DEVICEINTERFACE(lpdb);
                wxString device_name = wxString((const wchar_t *)pDevInf->dbcc_name).ToUTF8();
                wxString strVID,strPID,strSerialNumber;
                int share_0 = device_name.find(wxT("#"));
                int share_1 = device_name.find(wxT("#"),share_0+1);
                int share_2 = device_name.find(wxT("#"),share_1+1);
                strVID = device_name.substr(device_name.find(wxT("VID_"))+4,4);
                strPID = device_name.substr(device_name.find(wxT("PID_"))+4,4);
                strSerialNumber = device_name.substr(share_1+1,share_2-share_1-1);
                uint32_t vid=0,pid=0;
                bool ok;
                ok = strVID.ToUInt(&vid,16);
                ok = strPID.ToUInt(&pid,16);
                USBDeviceRemove((int)vid,(int)pid,strSerialNumber);
            }
            break;
        case DBT_DEVNODES_CHANGED:
        {

        }
        break;
        }
    }
    return wxFrame::MSWWindowProc(message, wParam, lParam);
}

const GUID GUID_DEVICEINTERFACE_LIST[] = {
    // {0x8FA230A2, 0xEBF0, 0x4C49, { 0xA2, 0xD6, 0x5A, 0x84, 0x85, 0x3B, 0x64, 0xD7 } },
    // {0xa5dcbf10, 0x6530, 0x11d2, { 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed } },//S1 Max
    {0x60000001, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },//EG01
};

bool MainFrame::RegisterUSBDeviceNotification(void)
{
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    HDEVNOTIFY hDeviceNotify;

    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    for(int i=0; i<sizeof(GUID_DEVICEINTERFACE_LIST)/sizeof(GUID); i++)
    {
        NotificationFilter.dbcc_classguid = GUID_DEVICEINTERFACE_LIST[i];

        hDeviceNotify = RegisterDeviceNotification(
            (HANDLE)this->m_hWnd,      // events recipient
            &NotificationFilter,        // type of device
            DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
            );
        if (NULL == hDeviceNotify)
        {
            wxLogInfo("RegisterDeviceNotification failed!");
            return false;
        }
    }
    return true;
}

#elif defined __APPLE__

// IOServiceAddMatchingNotification 回调函数
// refCon 是注册时传递的参数，比如对象指针等
void deviceAdded(void *refCon, io_iterator_t iterator) {
    io_service_t usb_device = IOIteratorNext(iterator);
    while (usb_device)
    {
        // 设备名称
        CFStringRef device_name = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(usb_device, CFSTR(kUSBProductString), kCFAllocatorDefault, 0));
        if (!device_name) {
            device_name = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(usb_device, CFSTR(kUSBVendorString), kCFAllocatorDefault, 0));
        }
        // if (!device_name) {
        //     device_name = CFStringCreateWithCString(kCFAllocatorDefault, "<Unknown>", kCFStringEncodingUTF8);
        // }
        if(device_name)
        {
            // 获取 vip 和 pid
            CFTypeRef cf_vendor, cf_product;
            cf_vendor = (CFTypeRef)IORegistryEntrySearchCFProperty(usb_device, kIOServicePlane, CFSTR(kUSBHostMatchingPropertyVendorID), kCFAllocatorDefault,
                                                                kIORegistryIterateRecursively | kIORegistryIterateParents);

            cf_product = (CFTypeRef)IORegistryEntrySearchCFProperty(usb_device, kIOServicePlane, CFSTR(kUSBHostMatchingPropertyProductID), kCFAllocatorDefault,
                                                                    kIORegistryIterateRecursively | kIORegistryIterateParents);
            SInt32 vendor_id = 0, product_id = 0;
            if (cf_vendor && cf_product && CFNumberGetValue((CFNumberRef)cf_vendor, kCFNumberSInt32Type, &vendor_id) &&
                    CFNumberGetValue((CFNumberRef)cf_product, kCFNumberSInt32Type, &product_id))
            {
                ssize_t len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(device_name), kCFStringEncodingUTF8);
                char *buf = new char[len];
                CFStringGetCString(device_name, buf, len, kCFStringEncodingUTF8);
                wxLogInfo(wxString::Format("Device added:%s, vid 0x%04x, pid 0x%04x.", buf,vendor_id, product_id));
                delete[] buf;
                MyEventMainFrame event(mEVT_DEVICE_ARRIVAL,wxID_ANY);
                event.SetUSB_VID(0x8085);
                event.SetUSB_PID(0x0020);
                if(refCon != nullptr)
                {
                    MainFrame *win = (MainFrame *)refCon;
                    wxPostEvent(win,event);
                }
            }
            if (cf_vendor)
                CFRelease(cf_vendor);
            if (cf_product)
                CFRelease(cf_product);
            CFRelease(device_name);
        }
        IOObjectRelease(usb_device);
        usb_device = IOIteratorNext(iterator);
    }
}

void deviceRemoved(void *refCon, io_iterator_t iterator) {
    io_service_t usb_device = IOIteratorNext(iterator);
    while (usb_device)
    {
        // 设备名称
        CFStringRef device_name = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(usb_device, CFSTR(kUSBProductString), kCFAllocatorDefault, 0));
        if (!device_name) {
            device_name = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(usb_device, CFSTR(kUSBVendorString), kCFAllocatorDefault, 0));
        }
        // if (!device_name) {
        //     device_name = CFStringCreateWithCString(kCFAllocatorDefault, "<Unknown>", kCFStringEncodingUTF8);
        // }
        if(device_name)
        {
            // 获取 vip 和 pid
            CFTypeRef cf_vendor, cf_product;
            cf_vendor = (CFTypeRef)IORegistryEntrySearchCFProperty(usb_device, kIOServicePlane, CFSTR(kUSBHostMatchingPropertyVendorID), kCFAllocatorDefault,
                                                                kIORegistryIterateRecursively | kIORegistryIterateParents);

            cf_product = (CFTypeRef)IORegistryEntrySearchCFProperty(usb_device, kIOServicePlane, CFSTR(kUSBHostMatchingPropertyProductID), kCFAllocatorDefault,
                                                                    kIORegistryIterateRecursively | kIORegistryIterateParents);
            SInt32 vendor_id = 0, product_id = 0;
            if (cf_vendor && cf_product && CFNumberGetValue((CFNumberRef)cf_vendor, kCFNumberSInt32Type, &vendor_id) &&
                    CFNumberGetValue((CFNumberRef)cf_product, kCFNumberSInt32Type, &product_id))
            {
                ssize_t len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(device_name), kCFStringEncodingUTF8);
                char *buf = new char[len];
                CFStringGetCString(device_name, buf, len, kCFStringEncodingUTF8);
                wxLogInfo(wxString::Format("Device removed:%s, vid 0x%04x, pid 0x%04x.", buf,vendor_id, product_id));
                delete[] buf;
                MyEventMainFrame event(mEVT_DEVICE_REMOVED,wxID_ANY);
                event.SetUSB_VID(0x8085);
                event.SetUSB_PID(0x0020);
                if(refCon != nullptr)
                {
                    MainFrame *win = (MainFrame *)refCon;
                    wxPostEvent(win,event);
                }
            }
            if (cf_vendor)
                CFRelease(cf_vendor);
            if (cf_product)
                CFRelease(cf_product);
            CFRelease(device_name);
        }

        IOObjectRelease(usb_device);
        usb_device = IOIteratorNext(iterator);
    }
}


bool MainFrame::RegisterUSBDeviceNotification(void)
{
    CFMutableDictionaryRef match_dict,match_dict_remove;
    io_iterator_t add_iterator,remove_iterator;

    // 创建 I/O Kit 通知端口
    notify_prot = IONotificationPortCreate(kIOMasterPortDefault);

    // 创建匹配字典，可以指定要监听的设备的厂商 ID 和产品 ID
    match_dict = IOServiceMatching(kIOUSBDeviceClassName);
    match_dict_remove = IOServiceMatching(kIOUSBDeviceClassName);
    SInt32 vendor_id = 0x8085;
    SInt32 product_id = 0x0020;
    CFDictionarySetValue(match_dict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id));
    CFDictionarySetValue(match_dict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product_id));
    CFDictionarySetValue(match_dict_remove, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id));
    CFDictionarySetValue(match_dict_remove, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product_id));

    // 创建异步通知端口
    // kIOMatchedNotification 添加
    // kIOTerminatedNotification 移除
    kern_return_t result;
    result = IOServiceAddMatchingNotification(notify_prot, kIOMatchedNotification, match_dict, deviceAdded, this, &add_iterator);
    if (result != KERN_SUCCESS) {
        fprintf(stderr, "IOServiceAddMatchingNotification error: %d. \n", result);
        return false;
    }
    result = IOServiceAddMatchingNotification(notify_prot, kIOTerminatedNotification, match_dict_remove, deviceRemoved, this, &remove_iterator);
    if (result != KERN_SUCCESS) {
        fprintf(stderr, "IOServiceAddMatchingNotification error: %d. \n", result);
        return false;
    }
    // 初始化的时候要调用一次，不然没回调，也可以在这时枚举当前已有设备
    // 可以使用空的处理来跳过
    deviceAdded(nullptr, add_iterator);
    deviceRemoved(nullptr, remove_iterator);

    // 将通知端口连接到一个运行循环结构中
    // 运行循环属于 Core Foundation 变成模型，实现了消息循环，当消息到达通知端口时，用户提供的回调函数会被调用
    CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notify_prot), kCFRunLoopDefaultMode);

    // 进入主运行循环，等待设备插入或拔出事件
    // 如果是放到 Qt 事件循环里就不需要这个
    // CFRunLoopRun();

    // 释放
    // IONotificationPortDestroy(notify_prot);
    return true;
}
#endif


void MainFrame::USBDeviceArrival(unsigned int vid, unsigned int pid,wxString serialNum)
{
    wxLogInfo("USBDeviceArrival");
    if(pid == usb_device_pid && vid == usb_device_vid)
    {
        if(!usb_comm->IsConnected())
        {
            tim_usb_delay->Start(300,true);
        }
    }
}

void MainFrame::USBDeviceRemove(unsigned int vid, unsigned int pid,wxString serialNum)
{
    wxLogInfo("USBDeviceRemoval");
    if(pid == usb_device_pid && vid == usb_device_vid)
    {
        tim_usb_delay->Stop();
        usb_comm->Disconnect();
        SetTitle(wxT("DOUBLE声学"));
        if(proc_dig->IsShown())
        {
            proc_dig->EndModal(wxID_OK);
        }
    }
}


void MainFrame::OnTimerUSBDelay(wxTimerEvent& event)
{
    usb_comm->SetVidPid(usb_device_vid, usb_device_pid);
    usb_comm->SetInterfaceNumber(usb_device_interface_num);
    bool rc = usb_comm->Connect();
    if(rc)
    {
        // std::thread syncDataThread(&MainFrame::SyncDeviceData, this);
        // syncDataThread.detach(); // 分离线程，使得主线程不需要等待扫描线程完成
        // while(syncDataThread.joinable())
        // {
        //     std::this_thread::sleep_for(std::chrono::milliseconds(100));
        // }
        // proc_dig->EndModal(wxID_OK);
        SyncDeviceData();
        //proc_dig->EndModal(wxID_OK);
        SetTitle(windowTitle);
    }
    else
    {

    }
}

void MainFrame::SyncDeviceData(void)
{
    int i=0;

    // while(usb_comm->IsConnected())
    // while(i<100)
    // {
    //     i++;
    //     proc_dig->Update(i);
    //     std::this_thread::sleep_for(std::chrono::milliseconds(10));
    // }
    PanelChorus::param_struct param_struct_chorus;
    PanelReverb::param_struct param_struct_reverb;
    PanelDelay::param_struct  param_struct_delay;
    PanelWah::param_struct  param_struct_wah;
    PanelDistortion::param_struct param_struct_distortion;

    CommandProcess::t_dev_info info;
    if(cmd_proc->get_device_info(info) == CommandProcess::SUCCESS)
    {
        wxLogInfo("Get device info success");
        wxLogInfo(wxString::Format("hw ver:%d",info.hw_ver ));
        wxLogInfo(wxString::Format("fw major:%d",info.fw_ver_major ));
        wxLogInfo(wxString::Format("fw minor:%d",info.fw_ver_minor ));
        wxLogInfo(wxString::Format("name:%s",(char *)info.name ));
        info.name[15] = '\0';
        wxString title;
        title = GetTitle() + wxString::Format(" - %s(HW:%d,FW:%d.%d)",(char *)info.name,info.hw_ver,info.fw_ver_major,info.fw_ver_minor);
        windowTitle = title;
//        SetTitle(title);
        // std::thread syncDataThread(&MainFrame::SyncDeviceData, this);
        // syncDataThread.detach(); // 分离线程，使得主线程不需要等待扫描线程完成
        wxXmlNode *node_root;
        wxXmlNode *node_preset;
        int max_preset = 1;
    #if PANEL_EN_REVERB
        if(usb_comm->IsConnected())
        {
            panel_reverb->PresetListClear();
            node_root = data_save->GetEffectParamNode(DataSave::NODE_REVERB);
            for(int preset = 0; preset < max_preset; preset++)
            {
                if(cmd_proc->get_param_reverb(preset,param_struct_reverb) == CommandProcess::SUCCESS)
                {
                    panel_reverb->SetParamEnable(param_struct_reverb.enable);
                    panel_reverb->SetParamWet(param_struct_reverb.wet);
                    panel_reverb->SetParamDry(param_struct_reverb.dry);
                    panel_reverb->SetParamDamping(param_struct_reverb.damp);
                    panel_reverb->SetParamFeedback(param_struct_reverb.feedback);
                    panel_reverb->SetParamTone(param_struct_reverb.tone);
                    proc_dig->Update(30);
                    node_preset = DataSave::FindChildNode(node_root,wxString::Format("reverb-%d",preset+1));
                    if(node_preset)
                    {
                        panel_reverb->WriteToXML(node_preset);
                        panel_reverb->AddPresetList(node_preset->GetName());
                    }
                    // wxLogInfo(wxString::Format("%s enable=\"%d\" dry=\"%f\" wet=\"%f\" damp=\"%f\" tone=\"%f\" feedback=\"%f\"",
                    //                     node_preset->GetName(),
                    //                     param_struct_reverb.enable,
                    //                     param_struct_reverb.dry,
                    //                     param_struct_reverb.wet,
                    //                     param_struct_reverb.damp,
                    //                     param_struct_reverb.tone,
                    //                     param_struct_reverb.feedback));
                }
            }
            panel_reverb->SetPresetIndex(0);
        }
    #endif
    #if PANEL_EN_CHORUS
        if(usb_comm->IsConnected())
        {
            node_root = data_save->GetEffectParamNode(DataSave::NODE_CHORUS);
            panel_chorus->PresetListClear();
            for(int preset = 0; preset < max_preset; preset++)
            {
                if(cmd_proc->get_param_chorus(preset,param_struct_chorus) == CommandProcess::SUCCESS)
                {
                    panel_chorus->SetParamEnable(param_struct_chorus.enable);
                    panel_chorus->SetParamDry(param_struct_chorus.dry);
                    panel_chorus->SetParamWet(param_struct_chorus.wet);
                    panel_chorus->SetParamPitch(param_struct_chorus.pitch);
                    panel_chorus->SetParamRate(param_struct_chorus.rate);
                    panel_chorus->SetParamTone(param_struct_chorus.tone);
                    proc_dig->Update(40);
                    node_preset = DataSave::FindChildNode(node_root,wxString::Format("chorus-%d",preset+1));
                    if(node_preset)
                    {
                        panel_chorus->WriteToXML(node_preset);
                        panel_chorus->AddPresetList(node_preset->GetName());
                    }
                }
            }
            panel_chorus->SetPresetIndex(0);
        }
    #endif
    #if PANEL_EN_DELAY
        if(usb_comm->IsConnected())
        {
            panel_delay->PresetListClear();
            node_root = data_save->GetEffectParamNode(DataSave::NODE_DELAY);
            for(int preset = 0; preset < max_preset; preset++)
            {
                if(cmd_proc->get_param_delay(preset,param_struct_delay) == CommandProcess::SUCCESS)
                {
                    panel_delay->SetParamEnable(param_struct_delay.enable);
                    panel_delay->SetParamTime(param_struct_delay.time_ms);
                    panel_delay->SetParamFeedback(param_struct_delay.feedback);
                    panel_delay->SetParamWet(param_struct_delay.wet);
                    panel_delay->SetParamTone(param_struct_delay.tone);
                    proc_dig->Update(50);
                    node_preset = DataSave::FindChildNode(node_root,wxString::Format("delay-%d",preset+1));
                    if(node_preset)
                    {
                        panel_delay->WriteToXML(node_preset);
                        panel_delay->AddPresetList(node_preset->GetName());
                    }
                }
            }
            panel_delay->SetPresetIndex(0);
        }
    #endif
    #if PANEL_EN_WAH
        if(usb_comm->IsConnected())
        {
            panel_wah->PresetListClear();
            node_root = data_save->GetEffectParamNode(DataSave::NODE_WAH);
            for(int preset = 0; preset < max_preset; preset++)
            {
                if(cmd_proc->get_param_wah(preset,param_struct_wah) == CommandProcess::SUCCESS)
                {
                    panel_wah->SetParamEnable(param_struct_wah.enable);
                    panel_wah->SetParamSpeed(param_struct_wah.speed);
                    panel_wah->SetParamFilterFreqCenter(param_struct_wah.filter_freq_center);
                    panel_wah->SetParamFilterFreqWidth(param_struct_wah.filter_freq_width);
                    panel_wah->SetParamFilterQ(param_struct_wah.filter_q);
                    panel_wah->SetParamFilterGain(param_struct_wah.filter_gain);
                    proc_dig->Update(50);
                    node_preset = DataSave::FindChildNode(node_root,wxString::Format("wah-%d",preset+1));
                    if(node_preset)
                    {
                        panel_wah->WriteToXML(node_preset);
                        panel_wah->AddPresetList(node_preset->GetName());
                    }
                    // wxLogInfo(wxString::Format("%s enable=\"%d\" speed=\"%f\" filter_q=\"%f\" filter_gain=\"%f\" filter_freq_center=\"%f\" filter_freq_width=\"%f\"",
                    //                     node_preset->GetName(),
                    //                     param_struct_wah.enable,
                    //                     param_struct_wah.speed,
                    //                     param_struct_wah.filter_q,
                    //                     param_struct_wah.filter_gain,
                    //                     param_struct_wah.filter_freq_center,
                    //                     param_struct_wah.filter_freq_width));
                }
            }
            panel_wah->SetPresetIndex(0);
        }
    #endif
    #if PANEL_EN_DISTORTION
        if(usb_comm->IsConnected())
        {
            int dist_sub_preset_max = 2;
            panel_distortion->PresetListClear();
            node_root = data_save->GetEffectParamNode(DataSave::NODE_DISTORTION);
            for(int preset = 0; preset < (dist_sub_preset_max*max_preset); preset++)
            {
                if(cmd_proc->get_param_distortion(preset,param_struct_distortion) == CommandProcess::SUCCESS)
                {
                    // if(preset == 0)
                    {
                        // panel_distortion->SetPresetIndex(0);
                        panel_distortion->SetParamEnable(param_struct_distortion.enable);
                        panel_distortion->SetParamDrive(param_struct_distortion.drive);
                        panel_distortion->SetParamPreGain(param_struct_distortion.gain_input);
                        panel_distortion->SetParamPostGain(param_struct_distortion.gain_output);
                        panel_distortion->SetParamTone(param_struct_distortion.tone);
                        panel_distortion->SetParamFreq(param_struct_distortion.freq);
                        panel_distortion->SetParamWidth(param_struct_distortion.bandwidth);
                        for(int i = 0; i < DISTORTION_EQ_MAX; i++)
                        {
                            if(cmd_proc->get_param_distortion_eq(preset,i,param_struct_distortion) == CommandProcess::SUCCESS)
                            {
                                panel_distortion->SetParamEq(i,param_struct_distortion.eq[i]);
                            }
                        }
                        node_preset = DataSave::FindChildNode(node_root,wxString::Format("distortion%d-%d",(preset/dist_sub_preset_max)+1,(preset%dist_sub_preset_max)+1));
                        if(node_preset)
                        {
                            panel_distortion->WriteToXML(node_preset);
                            panel_distortion->AddPresetList(node_preset->GetName());
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_enable, param_struct_distortion.enable ? "1" : "0");
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_drive, mDoubleToString(param_struct_distortion.drive).c_str());
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_postgain, mDoubleToString(param_struct_distortion.gain_output).c_str());
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_tone, mDoubleToString(param_struct_distortion.tone).c_str());
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_pregain, mDoubleToString(param_struct_distortion.gain_input).c_str());
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_bandwidth, mDoubleToString(param_struct_distortion.bandwidth).c_str());
                            // DataSave::NodeAttributesSetValue(node_preset,panel_distortion->attr_name_param_freq, mDoubleToString(param_struct_distortion.freq).c_str());
                        }
                    }
                    // proc_dig->Update(70);
                }
            }
            panel_distortion->SetPresetIndex(0);
        }
    #endif
    #if PANEL_EN_COMPRESSOR
    #endif
    }
    // proc_dig->Update(100);
//    std::this_thread::sleep_for(std::chrono::milliseconds(100));
//    proc_dig->EndModal(wxID_OK);
}

void MainFrame::OnProcessUpdate(MyEventMainFrame& event)
{
    if(proc_dig)
    {
        proc_dig->Update(event.GetProgress());
    }
}

void MainFrame::OnUsbArrival(MyEventMainFrame& event)
{
    // wxLogInfo("OnUSBDeviceArrival");
    USBDeviceArrival(event.GetUSB_VID(),event.GetUSB_PID(),event.GetUSB_SerialNumber());
}

void MainFrame::OnUsbRemoved(MyEventMainFrame& event)
{
    // wxLogInfo("OnUSBDeviceRemoved");
    USBDeviceRemove(event.GetUSB_VID(),event.GetUSB_PID(),event.GetUSB_SerialNumber());
}


void MainFrame::OnReverbParamChange(MyEventReverb &event)
{
#if PANEL_EN_REVERB
    wxPostEvent(cmd_proc,event);
#endif
}

void MainFrame::OnChorusParamChange(MyEventChorus &event)
{
#if PANEL_EN_CHORUS
    wxPostEvent(cmd_proc,event);
#endif
}
void MainFrame::OnDelayParamChange(MyEventDelay &event)
{
#if PANEL_EN_DELAY
    wxPostEvent(cmd_proc,event);
#endif
}
void MainFrame::OnWahParamChange(MyEventWah &event)
{
#if PANEL_EN_WAH
    wxPostEvent(cmd_proc,event);
#endif
}void MainFrame::OnDistortionParamChange(MyEventDistortion &event)
{
#if PANEL_EN_DISTORTION
    wxPostEvent(cmd_proc,event);
#endif
}
void MainFrame::OnCompressorParamChange(MyEventCompressor &event)
{
#if PANEL_EN_COMPRESSOR
    wxPostEvent(cmd_proc,event);
#endif
}
void MainFrame::OnEqualizerParamChange(MyEventEqualizer &event)
{
    wxPostEvent(cmd_proc,event);
}

void MainFrame::OnPresetParamChange(MyEventPreset &event)
{
    wxPostEvent(cmd_proc,event);
}
